﻿using System;
using System.Collections.ObjectModel;
using System.Collections.Specialized;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Ink;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;

namespace System.Windows.Controls
{
    /// <summary>
    /// Implements a custom layout and measuring container for the <see cref="CloudPanel"/>.
    /// </summary>
    public class CloudPanel : System.Windows.Controls.Panel
    {
        /// <summary>
        /// Instantiates a <see cref="CloudPanel"/> instance.
        /// </summary>
        public CloudPanel()
        {
            this.TileWidth = this.TileHeight = 96;

            scaleTransform = new ScaleTransform();
            this.RenderTransform = scaleTransform;
        }

        /// <summary>
        /// Identifies the <see cref="TileWidth"/> dependency property.
        /// </summary>
        public static readonly DependencyProperty TileWidthProperty = DependencyProperty.Register("TileWidth", typeof(double), typeof(CloudPanel), new PropertyMetadata(OnTileWidthPropertyChanged));

        /// <summary>
        /// Identifies the <see cref="TileHeight"/> dependency property.
        /// </summary>
        public static readonly DependencyProperty TileHeightProperty = DependencyProperty.Register("TileHeight", typeof(double), typeof(CloudPanel), new PropertyMetadata(OnTileHeightPropertyChanged));

        /// <summary>
        /// Identifies the <see cref="Magnification"/> dependency property.
        /// </summary>
        public static readonly DependencyProperty MagnificationProperty = DependencyProperty.Register("Magnification", typeof(double), typeof(CloudPanel), new PropertyMetadata(OnMagnificationPropertyChanged));

        private CloudView       _ParentView;
        private ScaleTransform  scaleTransform;
        private bool            magNoAnimations = false;

        internal CloudView ParentView
        {
            get { return _ParentView; }
            set 
            {
                if (null != _ParentView) _ParentView.ArrangerChanged -= this.HandleArrangerChanged;
                _ParentView = value;
                if (null != _ParentView) _ParentView.ArrangerChanged += new EventHandler(HandleArrangerChanged);
            }
        }

        /// <summary>
        /// Gets/Sets a double value that specifies the current magnification factor for the <see cref="CloudPanel"/> instance.
        /// </summary>
        public double Magnification
        {
            get { return (double)GetValue(MagnificationProperty); }
            set 
            { 
                magNoAnimations = true;
                SetValue(MagnificationProperty, value); 
                if (scaleTransform != null) scaleTransform.ScaleX = scaleTransform.ScaleY = value;
                this.InvalidateMeasure();
                this.InvalidateArrange();
                if (this.ParentView != null) this.ParentView.CenterScrollOrigin();
            }
        }

        private static void OnTileWidthPropertyChanged(DependencyObject obj, DependencyPropertyChangedEventArgs e)
        {
            if (obj is CloudPanel) ((CloudPanel)obj).TileWidth = (double)e.NewValue;
        }

        private static void OnTileHeightPropertyChanged(DependencyObject obj, DependencyPropertyChangedEventArgs e)
        {
            if (obj is CloudPanel) ((CloudPanel)obj).TileHeight = (double)e.NewValue;
        }

        private static void OnMagnificationPropertyChanged(DependencyObject obj, DependencyPropertyChangedEventArgs e)
        {
            if (obj is CloudPanel) ((CloudPanel)obj).Magnification = (double)e.NewValue;
        }

        /// <summary>
        /// Gets/Sets a double value that specifies the width of the <see cref="CloudViewItem"/> items in the panel.
        /// </summary>
        public double TileWidth
        {
            get { return (double)GetValue(TileWidthProperty); }
            set { SetValue(TileWidthProperty, value); }
        }

        /// <summary>
        /// Gets/Sets a double value that specifies the height of the <see cref="CloudViewItem"/> items in the panel.
        /// </summary>
        public double TileHeight
        {
            get { return (double)GetValue(TileHeightProperty); }
            set { SetValue(TileHeightProperty, value); }
        }

        /// <summary>
        /// (Override) Provides custom measurement functions for this <see cref="CloudPanel"/>.
        /// </summary>
        /// <param name="availableSize">The available size for the layout</param>
        /// <returns>The actual size for the layout</returns>
        protected override Size MeasureOverride(Size availableSize)
        {
            Size size = Size.Empty;

            for(int index = 0; index < this.Children.Count; index++)
            {
                UIElement element = this.Children[index];

                if (element is FrameworkElement)
                {
                    FrameworkElement frameElement = (FrameworkElement)element;
                    Rect bounds = LayoutHelper.GetBounds(frameElement);

                    if (bounds.Right > size.Width) size.Width = bounds.Right;
                    if (bounds.Bottom > size.Height) size.Height = bounds.Bottom;
                }
            }

            if (this.ParentView != null)
            {
                size.Width = this.ParentView.ViewportSize.Width * this.Magnification;
                size.Height = this.ParentView.ViewportSize.Height * this.Magnification;
            }

            return size;
        }

        void HandleArrangerChanged(object sender, EventArgs e)
        {
            this.InvalidateArrange();
        }

        /// <summary>
        /// (Override) Provides custom arrange functions for the <see cref="CloudPanel"/> instance.
        /// </summary>
        /// <param name="finalSize">The layout size for the control</param>
        /// <returns>The actual size of the layout</returns>
        protected override Size ArrangeOverride(Size finalSize)
        {
            if (this.ParentView != null)
            {
                Size size = new Size(this.TileWidth, this.TileHeight);
                this.ParentView.ArrangeCloudItems(size);
            }

            Point origin = new Point(0, 0);
            Point ptCenter = new Point(this.DesiredSize.Width / 2, this.DesiredSize.Height / 2);
            if (this.DesiredSize.Width == 0 && this.ParentView != null) ptCenter.X = this.ParentView.ActualWidth / 2;
            if (this.DesiredSize.Height == 0 && this.ParentView != null) ptCenter.Y = this.ParentView.ActualHeight / 2;

            for(int index = 0; index < this.Children.Count; index++)
            {
                UIElement element = this.Children[index];

                if (element is CloudViewItem)
                {
                    CloudViewItem viewItem = (CloudViewItem)element;
                    viewItem.ParentPanel = this;
                    viewItem.SetAnimationOrigin(ptCenter.X - viewItem.X, ptCenter.Y - viewItem.Y, 0);
                }

                if (element is FrameworkElement)
                {
                    FrameworkElement frameElement = (FrameworkElement)element;
                    double width = this.TileWidth;
                    double height = this.TileHeight;
                    Rect bounds = LayoutHelper.GetBounds(frameElement);

                    element.Arrange(new Rect(origin.X + bounds.X, origin.Y + bounds.Y, width, height));
                }
            }

            //Fire Animations
            if (this.ParentView != null && !magNoAnimations)
            {
                this.ParentView.AnimateCloudItems();
            }

            magNoAnimations = false;

            return finalSize;
        }
    }
}
